import { initState } from "./state.js";
import { compileToFunctions } from "./compiler/index.js";
import { mountComponent, callHook } from "./lifecycle.js";
import { mergeOptions } from "./util/index.js";
import { createElement, createTextNode } from "./vdom/index.js";

import Watcher from "./watcher.js";

export function initMixin(Vue) {
  Vue.prototype._init = function (options) {
    const vm = this;
     // render函数里面有_c _v _s方法需要定义
     Vue.prototype._c = function (...args) {
      // 创建虚拟dom元素
      return createElement(vm, ...args);
    };

    Vue.prototype._v = function (text) {
      // 创建虚拟dom文本
      return createTextNode(text);
    };
    Vue.prototype._s = function (val) {
      console.log(123333, val);
      // 如果模板里面的是一个对象  需要JSON.stringify
      return val == null
        ? ""
        : typeof val === "object"
        ? JSON.stringify(val)
        : val;
    };
    // 以下是生命周期：
    // 参数准备阶段,合并mixin参数,优先使用组件里面的配置
    vm.$options = mergeOptions(vm.constructor.options, options);
    callHook(vm, "beforeCreate"); //初始化数据之前
    initState(vm); // 初始化状态：data/method/computed/prop等
    callHook(vm, "create"); //初始化数据之前
    if (vm.$options.el) {
      vm.$mount(vm.$options.el); // 挂载组件
    }

   
  };

  Vue.mixin = function (mixin) {
    this.options = mergeOptions(this.options, mixin);
  };

  Vue.prototype.$watch = function (exprOrFn, cb, options) {
    const vm = this;
    let watcher = new Watcher(vm, exprOrFn, cb, { ...options, user: true });
    if (options.immediate) {
      cb();
    }
  };

  Vue.prototype.$mount = function (el) {
    const vm = this;
    const $options = vm.$options;
    el = document.querySelector(el);

    if (!$options.render) {
      // 如果存在template属性
      let template = $options.template;
      if (!template && el) {
        // 如果不存在render和template 但是存在el属性 直接将模板赋值到el所在的外层html结构（就是el本身 并不是父元素）
        template = el.outerHTML;
      }
      if (template) {
        // 最终需要把tempalte模板转化成render函数
        const render = compileToFunctions(template);
        $options.render = render;
      }
    }
    // 将当前组件实例挂载到真实的el节点上面
    return mountComponent(vm, el);
  };
}
